#import <Foundation/Foundation.h>
#import <objc/runtime.h>

#import "framework/FWCommon.h"

#import "PIEvent.h"

static UIColor* const kPIDefaultGreyEvent = [[UIColor colorWithRed:78.0/255.0 green:93.0/255.0 blue:108.0/255.0 alpha:1.0] retain];
static UIColor* const kPIReplaceGreyEvent = [[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:112.0/255.0 alpha:1.0] retain];


@implementation PIEvent

@synthesize rootKey, sectionTitle, sectionDetails, sectionStartInterval, sectionEndInterval, endDate, endDateTimeZone, endDateRaw, allDay, rangeStartDate, rangeEndDate, availability, firstAlarm, nextAlarm, hasAttendees, attendees, organiser, status, invitation, reminderInteract, shortInfoCalendar;


// ******************************************************************************************
#pragma mark -
#pragma mark Initialisation and object management

+ (PIEvent*)nativeEventWithKey:(NSString *)newKey version:(NSInteger)version title:(NSString *)newTitle icon:(NSString *)newIcon location:(NSString *)newLocation startDate:(NSDate *)newStart startDateTimeZone:(NSTimeZone *)newStartTimeZone startDateRaw:(NSTimeInterval)newStartRaw endDate:(NSDate *)newEnd endDateTimeZone:(NSTimeZone *)newEndTimeZone endDateRaw:(NSTimeInterval)newEndRaw allDay:(BOOL)newAllDay calendar:(NSString *)newCalendar calendarIcon:(NSString *)newCalIcon calendarColor:(UIColor *)newCalColor
{
    PIEvent* event = [[[PIEvent alloc] init] autorelease];
    
    event->key = [[NSString stringWithFormat:@"%@-%d", newKey, (NSInteger)newStartRaw] retain];
    event->rootKey = [newKey copy];
    event->objectVersion = version;
    event->native = YES;
    event->sensitivity = PISensitivityTypeNone;
    
    event->title = [newTitle copy];
    event->icon = [newIcon copy];

    if (newLocation && (newLocation.length > 0))
        [event->locations addObject:[PILocation piLocationWithTitle:newLocation]];

    event->allDay = newAllDay;
    [event setStartDate:newStart];
    [event setStartDateTimeZone:newStartTimeZone];
    event->startDateRaw = newStartRaw;
    [event setEndDate:newEnd];
    [event setEndDateTimeZone:newEndTimeZone];
    event->endDateRaw = newEndRaw;

    event->calendar = [newCalendar copy];
    event->calendarIcon = [newCalIcon copy];
    event->calendarColor = [newCalColor retain];
    
    return event;
}

+ (PIEvent*)piEventWithKey:(NSString *)newKey rootKey:(NSString *)newRootKey version:(NSInteger)version title:(NSString *)newTitle icon:(NSString *)newIcon location:(NSString *)newLocation startDate:(NSDate *)newStart startDateTimeZone:(NSTimeZone *)newStartTimeZone startDateRaw:(NSTimeInterval)newStartRaw endDate:(NSDate *)newEnd endDateTimeZone:(NSTimeZone *)newEndTimeZone endDateRaw:(NSTimeInterval)newEndRaw allDay:(BOOL)newAllDay calendar:(NSString *)newCalendar calendarIcon:(NSString *)newCalIcon calendarColor:(UIColor *)newCalColor
{
    PIEvent* event = [[[PIEvent alloc] init] autorelease];
    
    event->key = [newKey copy];
    event->rootKey = [newRootKey copy];
    event->objectVersion = version;
    event->native = NO;
    
    event->title = [newTitle copy];
    event->icon = [newIcon copy];
    
    if (newLocation && (newLocation.length > 0))
        [event->locations addObject:[PILocation piLocationWithTitle:newLocation]];

    event->allDay = newAllDay;
    [event setStartDate:newStart];
    [event setStartDateTimeZone:newStartTimeZone];
    event->startDateRaw = newStartRaw;
    [event setEndDate:newEnd];
    [event setEndDateTimeZone:newEndTimeZone];
    event->endDateRaw = newEndRaw;
    
    event->calendar = [newCalendar copy];
    event->calendarIcon = [newCalIcon copy];

    if ([newCalColor isEqual:kPIDefaultGreyEvent])
        event->calendarColor = [kPIReplaceGreyEvent retain];
    else
        event->calendarColor = [newCalColor retain];
    
    return event;
}

- (id)init
{
    self = [super init];
    if (self) {
        availability = kPIEventAvailabilityNotSupported;
        hasAttendees = NO;
        shortInfoCalendar = NO;
        
        self.rangeStartDate = [NSDate nullDate];
        self.rangeEndDate = [NSDate nullDate];
        
        self.firstAlarm = [NSDate nullDate];
        self.nextAlarm = [NSDate nullDate];
    }
    
    return self;
}

- (void)dealloc
{
    [rootKey release];

    [sectionTitle release];
    [sectionDetails release];

    [endDate release];
    [endDateTimeZone release];
    
    [rangeStartDate release];
    [rangeEndDate release];

    [firstAlarm release];
    [nextAlarm release];
    
    [organiser release];
    [attendees release];
    
    [super dealloc];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Object duplication

- (id)copyWithZone:(NSZone *)zone
{
    PIEvent* copy = [[[self class] allocWithZone:zone] init];
    
    copy->key = [self.key retain];
    copy->rootKey = [self.rootKey retain];
    copy->objectVersion = self.objectVersion;
    copy->native = self.native;
    
    copy->title = [self.title retain];
    copy->locations = [locations retain];
    copy->icon = [self.icon retain];
    
    [copy setSectionTitle:sectionTitle];
    
    [copy setStartDate:self.startDate];
    [copy setStartDateTimeZone:self.startDateTimeZone];
    [copy setEndDate:self.endDate];
    [copy setEndDateTimeZone:self.endDateTimeZone];

    copy->startDateRaw = self.startDateRaw;
    copy->endDateRaw = self.endDateRaw;
    copy->allDay = self.allDay;

    [copy setRangeStartDate:self.rangeStartDate];
    [copy setRangeEndDate:self.rangeEndDate];

    copy->calendar = [self.calendar retain];
    copy->calendarIcon = [self.calendarIcon retain];
    copy->calendarColor = [self.calendarColor retain];
    
    copy->availability = self.availability;
    copy->sensitivity = self.sensitivity;
    copy->status = self.status;
    copy->repeating = self.repeating;
    copy->hasAttendees = self.hasAttendees;
    copy->invitation = self.invitation;
    
    copy->shortInfoCalendar = self.shortInfoCalendar;
    
    [copy setFirstAlarm:self.firstAlarm];
    [copy setNextAlarm:self.nextAlarm];
    [copy setAlarms:self.alarms];

    return copy;
}

- (id)copyWithZone:(NSZone *)zone instance:(NSInteger)instance
{
    PIEvent* copy = [self copyWithZone:zone];
    NSString* newKey = [copy.key stringByAppendingFormat:@"[%d]", instance];
    
    [copy->key release];
    copy->key = [newKey retain];
    
    return copy;
}

- (id)copyInstance:(NSInteger)instance
{
    return [self copyWithZone:NULL instance:instance];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Debugging functions

- (NSString*)shortDescription
{
    return [NSString stringWithFormat:
            @"<%@: %p;"
            " key = %@;"
            " rootKey = %@;"
            " version = %i;"
            " title = %@;"
            " interact = %i;"
            " short = %i;"
            " startDate = %@;"
            " startDateRaw = %.0f;"
            " endDate = %@;"
            " endDateRaw = %.0f;"
            " allDay = %i;"
            " firstAlarm = %@;"
            " nextAlarm = %@>",
            [self class],
            self,
            self.key,
            self.rootKey,
            self.objectVersion,
            self.title,
            self.reminderInteract,
            self.shortInfoCalendar,
            self.startDate,
            self.startDateRaw,
            self.endDate,
            self.endDateRaw,
            self.isAllDay,
            self.firstAlarm,
            self.nextAlarm];
}

- (NSString*)description
{
    return [NSString stringWithFormat:
            @"<%@: %p;"
            " key = %@;"
            " rootKey = %@;"
            " title = %@;"
            " isNative = %i;"
            " version = %i;"
            " icon = %@;"
            " startDate = %@;"
            " startDateRaw = %.0f;"
            " endDate = %@;"
            " endDateRaw = %.0f;"
            " allDay = %i;"
            " calendar = %@;"
            " calendarIcon = %@;"
            " calendarColor = %@;"
            " firstAlarm = %@;"
            " nextAlarm = %@;"
            " alarms = %@;"
            " availability = %i;"
            " status = %i;"
            " organiser = %@;"
            " hasAttendees = %@;"
            " attendees = %@;"
            " interact = %i;"
            " short = %i;"
            " isRepeating = %@>",
            [self class],
            self,
            self.key,
            self.rootKey,
            self.title,
            self.native,
            self.objectVersion,
            self.icon,
            self.startDate,
            self.startDateRaw,
            self.endDate,
            self.endDateRaw,
            self.allDay,
            self.calendar,
            self.calendarIcon,
            self.calendarColor,
            self.firstAlarm,
            self.nextAlarm,
            self.alarms,
            self.availability,
            self.status,
            self.organiser,
            [NSNumber numberWithBool:self.hasAttendees],
            self.attendees,
            self.reminderInteract,
            self.shortInfoCalendar,
            [NSNumber numberWithBool:self.repeating]];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Information access

- (BOOL)hasDetails
{
    return (locations.count > 0) && !shortInfoCalendar;
}

@end


// ******************************************************************************************
#pragma mark -
#pragma mark Object access from arrays

@implementation NSArray (PIEvent)

- (NSArray*)piEventsForRootKey:(NSString*)key
{
    NSUInteger count = self.count;
    NSMutableArray* items = [NSMutableArray arrayWithCapacity:count];

    for (NSUInteger i = 0; i < count; ++i) {
        PIEvent* obj = [self objectAtIndex:i];
        if ([obj.rootKey isEqualToString:key])
            [items addObject:obj];
    }
    
    return items.count > 0 ? items : nil;
}

@end
